package com.zuoyeben123.testzybhtml.socket;

import android.util.Log;

import com.zuoyeben123.testzybhtml.protocol.ByteTpMessage;
import com.zuoyeben123.testzybhtml.protocol.NetInteger;
import com.zuoyeben123.testzybhtml.protocol.TextTpMessage;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Arrays;

/**
 * Socket收发器
 *
 * Created by wangliang on 2017/11/27.
 */

public abstract class SocketTransceiver implements Runnable {

    protected Socket socket;
    protected InetAddress addr;
    protected DataInputStream in;
    protected DataOutputStream out;
    private boolean runFlag;

    public SocketTransceiver(Socket socket) {
        this.socket = socket;
        this.addr = socket.getInetAddress();
    }

    public InetAddress getInetAddress() {
        return addr;
    }

    public void start() {
        runFlag = true;
        new Thread(this).start();
    }

    public void stop() {
        runFlag = false;
        try {
            if(socket != null)
                socket.shutdownInput();
            if(in != null)
                in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public boolean send(String s) {
        if(out != null) {
            try {
                byte[] data = new TextTpMessage(s).encode();
                if(data != null) {
                    Log.d("WLTest", "send data:" + Arrays.toString(data));
                    out.write(data);
                    out.flush();
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }
    public boolean send(byte[] msg) {
        if(out != null) {
            try {
                byte[] data = new ByteTpMessage(msg).encode();
                if(data != null) {
                    out.write(data);
                    out.flush();
                }
                data = null;
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;

    }
    @Override
    public void run() {
        try {
            in = new DataInputStream(this.socket.getInputStream());
            out = new DataOutputStream(this.socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
            runFlag = false;
        }
        while (runFlag) {
            try {
                byte[] lenData = new byte[4];
                in.read(lenData);
                NetInteger netlen = new NetInteger();
                netlen.parse(lenData, 0);
                int dataLen = netlen.getIntValue();
                System.out.println("收到数据包大小:" + dataLen);

                if(dataLen > 0) {
                    byte[] buffer = new byte[dataLen];
                    int offset = 0;
                    int len = 0;
                    int size = 0;

                    while (len < dataLen) {
                        size = in.read(buffer, offset + len, dataLen - offset - len);
                        len += size;
                    }
                    this.onReceive(addr, buffer);
                } else {
                    // 连接被断开(被动)
                    runFlag = false;
                }
            } catch (IOException e) {
                // 连接被断开(被动)
                runFlag = false;
            }
        }
        // 断开连接
        try {
            in.close();
            out.close();
            socket.close();
            in = null;
            out = null;
            socket = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.onDisconnect(addr);
    }

    /**
     * 接收到数据
     * <p>
     * 注意：此回调是在新线程中执行的
     *
     * @param addr
     *            连接到的Socket地址
     * @param data
     *            收到的数据
     */
    public abstract void onReceive(InetAddress addr, byte[] data);

    /**
     * 连接断开
     * <p>
     * 注意：此回调是在新线程中执行的
     *
     * @param addr
     *            连接到的Socket地址
     */
    public abstract void onDisconnect(InetAddress addr);
}
